<template>
  <div class="ll-calendar">
    <div class="ll-calendar-header">
      <div class="ll-calendar-header-subtitle">
        {{ current.replace(/-/g, " ") }}
      </div>
    </div>
    <div class="ll-calendar-month">
      <div class="month-prev" @click="onPrev">＜{{ prev }}月</div>
      <div class="month-current">{{ month }}月</div>
      <div class="month-next" @click="onNext">{{ next }}月＞</div>
    </div>

    <div class="ll-calendar-body">
      <div class="ll-calendar-week">
        <div class="week-item" v-for="item in week" :key="item">{{ item }}</div>
      </div>
      <div v-for="month in quarter" :key="month.month">
        <div class="ll-calendar-days" :month="month.month">
          <div
            class="jb-calendar-row"
            v-for="(row, index) in month.days"
            :key="index"
          >
            <div
              class="days-item"
              :class="{
                'is-minor': item.isMinor,
                'is-today': item.isToday,
                'is-current': item.isCurrent,
                'is-danger': item.isDanger,
              }"
              v-for="(item, index) in row"
              :key="index"
              @click="onChange(item)"
            >
              {{ Number(item.day) }}
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import dayjs from "dayjs";
let CalendarException = function CalendarException(message) {
  this.message = message;
  this.toString = function () {
    return this.constructor.name + ": " + this.message;
  };
};

let Calendar = function Calendar(firstWeekDay) {
  //properties
  this.firstWeekDay = firstWeekDay || 0; // 0 = Sunday
};

Calendar.prototype = {
  constructor: Calendar,
  weekStartDate(date) {
    let startDate = new Date(date.getTime());
    while (startDate.getDay() !== this.firstWeekDay) {
      startDate.setDate(startDate.getDate() - 1);
    }
    return startDate;
  },
  monthDates(year, month, dayFormatter, weekFormatter) {
    if (typeof year !== "number" || year < 1970) {
      throw new CalendarException("year must be a number >= 1970");
    }
    if (typeof month !== "number" || month < 0 || month > 11) {
      throw new CalendarException("month must be a number (Jan is 0)");
    }
    let weeks = [],
      week = [],
      i = 0,
      date = this.weekStartDate(new Date(year, month, 1));
    do {
      for (i = 0; i < 7; i++) {
        week.push(dayFormatter ? dayFormatter(date) : date);
        date = new Date(date.getTime());
        date.setDate(date.getDate() + 1);
      }
      weeks.push(weekFormatter ? weekFormatter(week) : week);
      week = [];
    } while (weeks.length < 6);
    return weeks;
  },
  monthDays(year, month) {
    let getDayOrZero = function getDayOrZero(date) {
      return date.getMonth() === month ? date.getDate() : 0;
    };
    return this.monthDates(year, month, getDayOrZero);
  },
  monthText(year, month) {
    if (typeof year === "undefined") {
      let now = new Date();
      year = now.getFullYear();
      month = now.getMonth();
    }
    let getDayOrBlank = function getDayOrBlank(date) {
      let s = date.getMonth() === month ? date.getDate().toString() : "  ";
      while (s.length < 2) s = " " + s;
      return s;
    };
    let weeks = this.monthDates(year, month, getDayOrBlank, function (week) {
      return week.join(" ");
    });
    return weeks.join("\n");
  },
};
let months = "JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC".split(" ");
for (let i = 0; i < months.length; i++) {
  Calendar[months[i]] = i;
}

export default {
  name: "BJCalendar",
  props: {
    months: {
      type: Array,
      default() {
        return [];
      },
    },
  },
  data() {
    return {
      swipe: 1,
      week: ["一", "二", "三", "四", "五", "六", "日"],
      current: dayjs().format("YYYY-MM-DD"),
    };
  },
  computed: {
    month() {
      return dayjs(this.current).format("MM");
    },
    prev() {
      return dayjs(this.current).subtract(1, "month").format("MM");
    },
    next() {
      return dayjs(this.current).add(1, "month").format("MM");
    },
    quarter() {
      const calendar = new Calendar(1);
      const [today_year, today_month, today_day] = dayjs()
        .format("YYYY-MM-DD")
        .split("-");
      return [this.current].map((month) => {
        const [curr_year, curr_month, curr_day] = month.split("-");
        const days = calendar
          .monthDates(Number(curr_year), Number(curr_month) - 1)
          .map((temp) => {
            return temp.map((item) => {
              const dayObj = dayjs(item);
              const [year, month, day] = dayObj.format("YYYY-MM-DD").split("-");
              const isMinor =
                [0, 6].includes(dayObj.day()) ||
                year !== curr_year ||
                month !== curr_month;
              const isToday =
                year === today_year &&
                month === today_month &&
                day === today_day;
              const isCurrent =
                year === curr_year && month === curr_month && day === curr_day;
              const isDanger = this.months.includes(`${year}-${month}-${day}`);
              return {
                year,
                month,
                day,
                isMinor,
                isToday,
                isCurrent,
                isDanger,
              };
            });
          });
        return {
          days,
          month,
        };
      });
    },
  },
  watch: {
    current(newVal, oldVal) {
      if (newVal !== oldVal) {
        this.$emit("change", newVal, oldVal);
      }
    },
  },
  activated() {
    this.current = dayjs().format("YYYY-MM-DD");
  },
  methods: {
    onPrev() {
      this.current = dayjs(this.current)
        .subtract(1, "month")
        .format("YYYY-MM-DD");
    },
    onNext() {
      this.current = dayjs(this.current).add(1, "month").format("YYYY-MM-DD");
    },
    onChange(data) {
      this.current = [data.year, data.month, data.day].join("-");
    },
  },
};
</script>

<style lang="scss" scoped>
.ll-calendar {
  background: #ffffff;
  padding: 26px 20px 30px 20px;

  .ll-calendar-header {
    display: flex;
    justify-content: space-between;
    align-items: center;

    .ll-calendar-header-title {
      font-size: 20px;
      font-family: PingFang SC-Regular, PingFang SC, sans-serif;
      font-weight: 400;
      color: rgba(0, 0, 0, 0.9);
      line-height: 23px;
      letter-spacing: 1px;
    }

    .ll-calendar-header-subtitle {
      font-size: 16px;
      font-family: PingFang SC-Regular, PingFang SC, sans-serif;
      font-weight: 400;
      color: rgba(0, 0, 0, 0.7);
      line-height: 19px;
    }
  }

  .ll-calendar-month {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 16px;

    .month-current {
      font-size: 20px;
      font-family: PingFang SC-Medium, PingFang SC, sans-serif;
      font-weight: 500;
      color: #000000;
      line-height: 23px;
    }

    .month-prev,
    .month-next {
      font-size: 18px;
      font-family: PingFang SC-Regular, PingFang SC, sans-serif;
      font-weight: 400;
      color: rgba(0, 0, 0, 0.5);
      line-height: 21px;
      display: flex;
      align-items: center;
      margin: 0 2px;
    }
  }

  .ll-calendar-body {
    border: 1px solid rgba(0, 0, 0, 0.1);
    border-radius: 12px;
    margin-top: 11px;

    .ll-calendar-week {
      display: flex;
      justify-content: space-around;
      background: rgba(37, 142, 255, 0.04);
      height: 40px;
      align-items: center;
      border-radius: 12px 12px 0 0;

      .week-item {
        flex: 1;
        text-align: center;
        font-size: 14px;
        font-family: PingFang SC-Regular, PingFang SC, sans-serif;
        font-weight: 400;
        color: rgba(0, 0, 0, 0.5);
        line-height: 16px;
      }
    }

    .ll-calendar-days {
      padding: 10px 0;

      .jb-calendar-row {
        display: flex;
        justify-content: space-around;
      }

      .days-item {
        width: 38px;
        height: 38px;
        margin: 7px 2px;
        font-size: 15px;
        font-family: Helvetica Neue-Medium, Helvetica Neue, sans-serif;
        font-weight: 500;
        color: #000000;
        display: flex;
        justify-content: center;
        align-items: center;
        border-radius: 50%;

        &.is-minor {
          font-weight: 400;
          color: rgba(0, 0, 0, 0.5);
        }

        &.is-today {
          background: rgba(37, 142, 255, 0.2);
        }

        &.is-current {
          background: #258eff;
          color: #ffffff;
          font-weight: bold;
          font-family: Helvetica Neue-Bold, Helvetica Neue, sans-serif;
        }

        &.is-danger {
          position: relative;

          &::after {
            content: "";
            display: block;
            position: absolute;
            width: 6px;
            height: 6px;
            border-radius: 100%;
            bottom: 1px;
            left: 50%;
            transform: translateX(-50%);
            background: #ee412b;
          }
        }
      }
    }
  }
}
</style>
